template<typename T>
class shared_ptr
{
public:
    shared_ptr() : m_r(nullptr), m_p(nullptr) {}
    shared_ptr(T* p) : m_r(nullptr), m_p(p) {
        addReference();
    }
    shared_ptr(const shared_ptr<T>& sp) : m_r(sp.m_r), m_p(sp.m_p) {
        addReference();
    }
    shared_ptr(shared_ptr<T>&& sp) : m_r(sp.m_r), m_p(sp.m_p) {
        delete sp.m_p;
        sp.m_p = nullptr;
        delete sp.m_r;
        sp.m_r = nullptr;
    }
    virtual ~shared_ptr() {
        removeReference();
    }
    shared_ptr<T>& operator=(const shared_ptr<T>& sp) {
        if (this != &sp) {
            removeReference();
            this->m_r = sp.m_r;
            this->m_p = sp.m_p;
            addReference();
        }
        return *this;
    }
private:
    void addReference() {
        if (m_r) {
            ++(*m_r);
        } else {
            m_r = new int(1);
        }
    }
    void removeReference() {
        if (m_r) {
            --(*m_r);
            if (*m_r == 0) {
                delete m_r;
                m_r = nullptr;
                delete m_p;
                m_p = nullptr;
            }
        }
    }
private:
    int* m_r;
    T* m_p;
};